---
title: "Creating a Basic Grid"
description: "Learn to create and configure an AG Grid from scratch, covering row data, column definitions, grid options, formatting, and custom components."
---

Learn how to create and configure an AG Grid instance from scratch. This guide introduces the essential concepts required to build an interactive grid, including setting up row data, defining columns, applying grid options, formatting cell values, and adding custom components.

## Overview

In this tutorial you will:

1. [Create a basic grid](./deep-dive/#create-a-basic-grid)
1. [Load external data into the grid](./deep-dive/#load-new-data)
1. [Configure columns](./deep-dive/#configure-columns)
1. [Configure grid features](./deep-dive/#configure-the-grid)
1. [Format cell values](./deep-dive/#format-cell-values)
1. [Add custom components to cells](./deep-dive/#custom-cell-components)
1. [Hook into grid events](./deep-dive/#handle-grid-events)

Once complete, you'll have an interactive grid, with custom components and formatted data - Try it out for yourself by **sorting**, **filtering**, **resizing**, **selecting**, or **editing** data in the grid:

{% gridExampleRunner title="Testing Example" name="testing-example"  exampleHeight=550 /%}

## Create a Basic Grid

{% if isFramework("javascript") %}
<!-- Create a Basic Grid -->

Complete our [Quick Start](./getting-started/) (or open the example below in CodeSandbox / Plunker) to start with a basic grid, comprised of:

1) **Grid Options:** An object which holds all of the options for the grid, such as Row Data & Column Definitions.
1) **Row Data:** The data to be displayed.
1) **Column Definition:** Defines & controls grid columns.
1) **Container:** A div that contains and defines the grid's dimensions.
1) **Grid API:** Provides access to Grid API methods. Initialised when creating a new grid.

{% gridExampleRunner title="Basic Example" name="basic-example"  exampleHeight=220 /%}

{% /if %}

{% if isFramework("react") %}
<!-- Create a Basic Grid -->

Complete our [Quick Start](./getting-started/) (or open the example below in CodeSandbox / Plunker) to start with a basic grid, comprised of:

1) **Row Data:** The data to be displayed.
1) **Column Definition:** Defines & controls grid columns.
1) **Container:** A div that contains the grid and defines it's dimensions.
1) **Grid Component:** The `AgGridReact` component with **Row Data** and **Column Definition** props.

{% gridExampleRunner title="Basic Example" name="basic-example"  exampleHeight=220 /%}

_Note: `rowData` and `columnDefs` arrays use the `useState` hook. We recommend `useState` if the data is mutable, otherwise `useMemo` is preferable. Read our [Best Practices](./react-hooks/) guide to learn more about using React hooks with AG Grid._

{% /if %}

{% if isFramework("angular") %}
<!-- Create a Basic Grid -->

Complete our [Quick Start](./getting-started/) (or open the example below in CodeSandbox / Plunker) to start with a basic grid, comprised of:

1) **Row Data:** The data to be displayed.
1) **Column Definition:** Defines & controls grid columns.
1) **Grid Component:** The `ag-grid-angular` component, with Dimensions, Row Data, and Column Definition attributes

{% gridExampleRunner title="Basic Example" name="basic-example"  exampleHeight=220 /%}

{% /if %}

{% if isFramework("vue") %}
<!-- Create a Basic Grid -->

Complete our [Quick Start](./getting-started/) (or open the example below in CodeSandbox / Plunker) to start with a basic grid, comprised of:

1) **Row Data:** The data to be displayed.
1) **Column Definition:** Defines & controls grid columns.
1) **Grid Component:** The `ag-grid-vue` component, with Dimensions, Row Data, and Column Definition attributes

{% gridExampleRunner title="Basic Example" name="basic-example"  exampleHeight=220 /%}

{% /if %}

## Load New Data

{% if isFramework("javascript") %}
<!-- Load New Data -->

The Grid API provides a way of interacting with the grid. To update the data within the grid, we can use the `setGridOption` API. Let's test this by fetching some data and updating our grid with the response:

```jsx
fetch('https://www.ag-grid.com/example-assets/space-mission-data.json')
    .then(response => response.json())
    .then((data: any) => gridApi.setGridOption('rowData', data))
```

Now that we're loading data from an external source, we can empty our `rowData` array (which will allow the grid to display a loading spinner whilst the data is being fetched) and update our `colDefs` to match the new dataset:

```jsx
const gridOptions = {
    rowData: [],
    colDefs: [
        { field: "mission" },
        { field: "company" },
        { field: "location" },
        { field: "date" },
        { field: "price" },
        { field: "successful" },
        { field: "rocket" }
    ]
}
```

When we run our application, we should see a grid with ~1,400 rows of new data, and new column headers to match:

{% gridExampleRunner title="Updating Example" name="updating-example"  exampleHeight=550 /%}

_Note: There are a large number of APIs available. See our [API Docs](./grid-api/) for an exhaustive list._


{% /if %}

{% if isFramework("react") %}
<!-- Load New Data -->

As `rowData` is a reactive property, any updates to its state will be reflected in the grid. Let's test this by fetching some data from an external server and updating `rowData` with the response:

```jsx
// Fetch data & update rowData state
useEffect(() => {
    fetch('https://www.ag-grid.com/example-assets/space-mission-data.json') // Fetch data from server
        .then(result => result.json()) // Convert to JSON
        .then(rowData => setRowData(rowData)); // Update state of `rowData`
}, [])
```

Now that we're loading data from an external source, we can empty our `rowData` array (which will allow the grid to display a loading spinner whilst the data is being fetched) and update our `colDefs` to match the new dataset:

```jsx
const GridExample = () => {
    // Row Data: The data to be displayed.
    const [rowData, setRowData] = useState([]);
    const [colDefs, setColDefs] = useState([
        { field: "mission" },
        { field: "company" },
        { field: "location" },
        { field: "date" },
        { field: "price" },
        { field: "successful" },
        { field: "rocket" }
    ]);
    // ...
}
```

When we run our application, we should see a grid with ~1,400 rows of new data, and new column headers to match:

{% gridExampleRunner title="Updating Example" name="updating-example"  exampleHeight=550 /%}

_Note: All properties that are not tagged as 'initial' are reactive. See our [API docs](./grid-options/) for a complete list._


{% /if %}

{% if isFramework("angular") %}
<!-- Load New Data -->

As rowData is a managed property, any updates to its value will be reflected in the grid. Let's test this by fetching some data from an external server with [Angular's HttpClient](https://angular.dev/guide/http) and updating rowData with the response.

First we need to hook into the `gridReady` event by adding `(gridReady)="onGridReady($event)"` to the `ag-grid-angular` component:

```html
<!-- The AG Grid component, with various Grid Option properties -->
<ag-grid-angular
    style="width: 100%; height: 550px;"
    [rowData]="rowData"
    [columnDefs]="colDefs"
    (gridReady)="onGridReady($event)"
/>
```

_Note: [Grid Events](./deep-dive/#handle-grid-events) are covered in more detail later on_

And then executing a HTTP request when the onGridReady event is fired, subscribing to the result to update our rowData asynchronously:

```ts
// Load data into grid when ready
onGridReady(params: GridReadyEvent) {
    this.http
        .get<any[]>('https://www.ag-grid.com/example-assets/space-mission-data.json')
        .subscribe(data => this.rowData = data);
}
```

Finally, now that we're loading data from an external source, we can empty our `rowData` array (which will allow the grid to display a loading spinner whilst the data is being fetched) and update our `colDefs` to match the new dataset:

```jsx
export class AppComponent {
    // Row Data: The data to be displayed.
    rowData: IRow[] = [];
    colDefs: ColDef[] = [
        { field: "mission" },
        { field: "company" },
        { field: "location" },
        { field: "date" },
        { field: "price" },
        { field: "successful" },
        { field: "rocket" }
    ];
    // ...
}
```

When we run our application, we should see a grid with ~1,400 rows of new data, and new column headers to match:

{% gridExampleRunner title="Updating Example" name="updating-example"  exampleHeight=550 /%}

_Note: All [Grid Option](./grid-options/) properties tagged as 'managed' are automatically updated when their value changes._


{% /if %}

{% if isFramework("vue") %}
<!-- Load New Data -->

As rowData is a managed property, any updates to its value will be reflected in the grid. Let's test this by fetching some data from an external server and updating rowData with the response.

```jsx
// Fetch data when the component is mounted
onMounted(async () => {
    rowData.value = await fetchData();
});

const fetchData = async () => {
    const response = await fetch('https://www.ag-grid.com/example-assets/space-mission-data.json');
    return response.json();
};
```

Now that we're loading data from an external source, we can empty our `rowData` array (which will allow the grid to display a loading spinner whilst the data is being fetched) and update our `colDefs` to match the new dataset:

```jsx
const App = {
    setup() {
        const rowData = ref([]);
        const colDefs = ref([
            { field: "mission" },
            { field: "company" },
            { field: "location" },
            { field: "date" },
            { field: "price" },
            { field: "successful" },
            { field: "rocket" }
        ]);
        // ...
    }
    // ...
}
```

When we run our application, we should see a grid with ~1,400 rows of new data, and new column headers to match:

{% gridExampleRunner title="Updating Example" name="updating-example"  exampleHeight=550 /%}

Note: All [Grid Option](./grid-options/) properties tagged as 'managed' are automatically updated when their value changes.


{% /if %}

## Configure Columns

{% if isFramework("javascript") %}
<!-- Configure Columns -->

Now that we have a basic grid with some arbitrary data, we can start to configure the grid with _**Column Properties**_.

Column Properties can be added to one or more columns to enable/disable column-specific features. Let's try this by adding the `filter: true` property to the 'mission' column:

```jsx
columnDefs: [
    { field: "mission", filter: true },
    // ...
],
```

We should now be able to filter the 'mission' column - you can test this by filtering for the 'Apollo' missions:

{% gridExampleRunner title="Configuring Columns Example" name="configure-columns-example"  exampleHeight=550 /%}

_Note: Column properties can be used to configure a wide-range of features; refer to our [Column Properties](./column-properties/) page for a full list of features._
{% /if %}

{% if isFramework("react") %}
<!-- Configure Columns -->

Now that we have a basic grid with some arbitrary data, we can start to configure the grid with _**Column Properties**_.

Column Properties can be added to one or more columns to enable/disable column-specific features. Let's try this by adding the `filter: true` property to the 'mission' column:

```jsx
const [colDefs] = useState([
    { field: "mission", filter: true },
    // ...
]);
```

We should now be able to filter the 'mission' column - you can test this by filtering for the 'Apollo' missions:

{% gridExampleRunner title="Configuring Columns Example" name="configure-columns-example"  exampleHeight=550 /%}

_Note: Column properties can be used to configure a wide-range of features; refer to our [Column Properties](./column-properties/) page for a full list of features._
{% /if %}

{% if isFramework("angular") %}
<!-- Configure Columns -->

Now that we have a basic grid with some arbitrary data, we can start to configure the grid with _**Column Properties**_.

Column Properties can be added to one or more columns to enable/disable column-specific features. Let's try this by adding the `filter: true` property to the 'mission' column:

```jsx
colDefs: ColDef[] = [
    { field: "mission", filter: true },
    // ...
];
```

We should now be able to filter the 'mission' column - you can test this by filtering for the 'Apollo' missions:

{% gridExampleRunner title="Configuring Columns Example" name="configure-columns-example"  exampleHeight=550 /%}

_Note: Column properties can be used to configure a wide-range of features; refer to our [Column Properties](./column-properties/) page for a full list of features._
{% /if %}

{% if isFramework("vue") %}
<!-- Configure Columns -->

Now that we have a basic grid with some arbitrary data, we can start to configure the grid with _**Column Properties**_.

Column Properties can be added to one or more columns to enable/disable column-specific features. Let's try this by adding the `filter: true` property to the 'mission' column:

```jsx
const colDefs = ref([
    { field: "mission", filter: true },
    // ...
];
```

We should now be able to filter the 'mission' column - you can test this by filtering for the 'Apollo' missions:

{% gridExampleRunner title="Configuring Columns Example" name="configure-columns-example"  exampleHeight=550 /%}

_Note: Column properties can be used to configure a wide-range of features; refer to our [Column Properties](./column-properties/) page for a full list of features._
{% /if %}

### Default Column Definitions

{% if isFramework("javascript") %}
<!-- Default Column Definitions -->

The example above demonstrates how to configure a single column. To apply this configuration across all columns we can use _**Default Column Definitions**_ instead. Let's make all of our columns filterable by adding the `defaultColDef` property to our Grid Options object, and setting `filter: true`:

```jsx
const gridOptions = {
    defaultColDef: {
        filter: true
    }
    // ...
}
```

The grid should now allow filtering on all columns:

{% gridExampleRunner title="Default Column Definitions Example" name="default-columns-example"  exampleHeight=550 /%}

_Note: Column Definitions take precedence over Default Column Definitions_


{% /if %}

{% if isFramework("react") %}
<!-- Default Column Definitions -->

The example above demonstrates how to configure a single column. To apply this configuration across all columns we can use _**Default Column Definitions**_ instead. Let's make all of our columns filterable by creating a `defaultColDef` object, setting `filter: true`, and passing this to the grid via the `defaultColDef` prop:

```jsx
// Apply settings across all columns
const defaultColDef = useMemo(() => ({
    filter: true // Enable filtering on all columns
}))

<div style={{ width: 600, height: 500 }}>
    <AgGridReact
        defaultColDef={defaultColDef}
        //...
    />
</div>
```

The grid should now allow filtering on all columns:

{% gridExampleRunner title="Default Column Definitions Example" name="default-columns-example"  exampleHeight=550 /%}

_Note: Column Definitions take precedence over Default Column Definitions_


{% /if %}

{% if isFramework("angular") %}
<!-- Default Column Definitions -->

The example above demonstrates how to configure a single column. To apply this configuration across all columns we can use _**Default Column Definitions**_ instead. Let's make all of our columns filterable by creating a `defaultColDef` object, setting `filter: true`, and passing this to our template:

```jsx
@Component({
    template:
    `
    <div class="content">
        <ag-grid-angular
            ...
            [defaultColDef]="defaultColDef"
        />
    </div>
    `,
    // ...
})

export class AppComponent {
// Default Column Definitions: Apply configuration across all columns
defaultColDef: ColDef = {
        filter: true
    }
    // ...
}
```

The grid should now allow filtering on all columns:

{% gridExampleRunner title="Default Column Definitions Example" name="default-columns-example"  exampleHeight=550 /%}

_Note: Column Definitions take precedence over Default Column Definitions_


{% /if %}

{% if isFramework("vue") %}
<!-- Default Column Definitions -->

The example above demonstrates how to configure a single column. To apply this configuration across all columns we can use _**Default Column Definitions**_ instead. Let's make all of our columns filterable by creating a `defaultColDef` object with the property `filter: true`:

```jsx
const App = {
    setup() {
        const defaultColDef = ref({
            filter: true
        });
        // ...
    }
    return {
        defaultColDef
        // ...
    };
    // ...
}
```

And then adding this to our `ag-grid-vue` component:

```jsx
const App = {
    template:
        `
        <ag-grid-vue
            style="width: 100%; height: 100%"
            :columnDefs="colDefs"
            :rowData="rowData"
            :defaultColDef="defaultColDef"
        >
        </ag-grid-vue>
        `,
    // ...
}
```

The grid should now allow filtering on all columns:

{% gridExampleRunner title="Default Column Definitions Example" name="default-columns-example"  exampleHeight=550 /%}

_Note: Column Definitions take precedence over Default Column Definitions_


{% /if %}

## Configure The Grid

{% if isFramework("javascript") %}
<!-- Configure The Grid-->

So far we've covered creating a grid, updating the data within the grid, and configuring columns. This section introduces **Grid Options**, which control functionality that extends across both rows & columns, such as Pagination and Row Selection.

To use Grid Options, simply add the relevant property to the Grid Options object. Let's try this by adding `pagination: true` to our Grid Options:

```jsx
const gridOptions: GridOptions = {
    pagination: true
    // ...
}
```

We should now see Pagination has been enabled on the grid:

{% gridExampleRunner title="Grid Options Example" name="grid-options-example"  exampleHeight=550 /%}

_Refer to our detailed [Grid Options](./grid-options/) documentation for a full list of options._


{% /if %}

{% if isFramework("react") %}
<!-- Configure The Grid-->

So far we've covered creating a grid, updating the data within the grid, and configuring columns. This section introduces **Grid Options**, which control functionality that extends across both rows & columns, such as Pagination and Row Selection.

Grid Options are passed to the grid component directly as props. Let's enable pagination by adding `pagination={true}`:

```jsx
<div style={{ width: 600, height: 500 }}>
    <AgGridReact
        // ...
        pagination={true} // Enable Pagination
    />
</div>
```

We should now see Pagination has been enabled on the grid:

{% gridExampleRunner title="Grid Options Example" name="grid-options-example"  exampleHeight=550 /%}

_Refer to our detailed [Grid Options](./grid-options/) documentation for a full list of options._


{% /if %}

{% if isFramework("angular") %}
<!-- Configure The Grid-->

So far we've covered creating a grid, updating the data within the grid, and configuring columns. This section introduces **Grid Options**, which control functionality that extends across both rows & columns, such as Pagination and Row Selection.

Grid Options are passed to the grid via attributes on the `ag-grid-angular` component. Let's enable pagination by adding `[pagination]="true"`:

```html
<!-- The AG Grid component, with various Grid Option properties -->
<ag-grid-angular
    ...
    [pagination]="true"
/>
```

We should now see Pagination has been enabled on the grid:

{% gridExampleRunner title="Grid Options Example" name="grid-options-example"  exampleHeight=550 /%}

_Refer to our detailed [Grid Options](./grid-options/) documentation for a full list of options._


{% /if %}

{% if isFramework("vue") %}
<!-- Configure The Grid-->

So far we've covered creating a grid, updating the data within the grid, and configuring columns. This section introduces **Grid Options**, which control functionality that extends across both rows & columns, such as Pagination and Row Selection.

Grid Options are added directly to the `ag-grid-vue` component. Let's test this out by adding the `:pagination="true"` to the grid:

```jsx
const App = {
    name: "App",
    template: 
        `
        <ag-grid-vue
            style="width: 100%; height: 100%"
            :columnDefs="colDefs"
            :rowData="rowData"
            :defaultColDef="defaultColDef"
            :pagination="true"
        >
        </ag-grid-vue>
        `,
    //...
}
```

We should now see Pagination has been enabled on the grid:

{% gridExampleRunner title="Grid Options Example" name="grid-options-example"  exampleHeight=550 /%}

_Refer to our detailed [Grid Options](./grid-options/) documentation for a full list of options._


{% /if %}

## Format Cell Values

{% if isFramework("javascript") %}
<!-- Format Cell Values-->

The data supplied to the grid usually requires some degree of formatting. For basic text formatting we can use **Value Formatters**.

**Value Formatters** are basic functions which take the value of the cell, apply some basic formatting, and return a new value to be displayed by the grid. Let's try this by adding the `valueFormatter` property to our 'price' column and returning the formatted value:

```jsx
columnDefs: [
    {
        field: "price",
        // Return formatted value
        valueFormatter: (params) => { return '£' + params.value.toLocaleString(); }
    },
],
```

The grid should now show the formatted value in the 'price' column:

{% gridExampleRunner title="Value Formatter Example" name="value-formatter-example"  exampleHeight=550 /%}

_Note: Read our [Value Formatter](./value-formatters/) page for more information on formatting cell values_


{% /if %}

{% if isFramework("react") %}
<!-- Format Cell Values-->

The data supplied to the grid usually requires some degree of formatting. For basic text formatting we can use **Value Formatters**.

**Value Formatters** are basic functions which take the value of the cell, apply some basic formatting, and return a new value to be displayed by the grid. Let's try this by adding the `valueFormatter` property to our 'price' column and returning the formatted value:

```jsx
const [colDefs] = useState([
    {
        field: "price",
        // Return a formatted string for this column
        valueFormatter: params => { return '£' + params.value.toLocaleString(); }
    },
    // ...
]);
```

The grid should now show the formatted value in the 'price' column:

{% gridExampleRunner title="Value Formatter Example" name="value-formatter-example"  exampleHeight=550 /%}

_Note: Read our [Value Formatter](./value-formatters/) page for more information on formatting cell values_


{% /if %}

{% if isFramework("angular") %}
<!-- Format Cell Values-->

The data supplied to the grid usually requires some degree of formatting. For basic text formatting we can use **Value Formatters**.

**Value Formatters** are basic functions which take the value of the cell, apply some basic formatting, and return a new value to be displayed by the grid. Let's try this by adding the `valueFormatter` property to our 'price' column and returning the formatted value:

```ts
colDefs: ColDef[] = [
    {
        field: "price",
        valueFormatter: params => { return '£' + params.value.toLocaleString(); } // Format with inline function
    },
    // ...
];
```

The grid should now show the formatted value in the 'price' column:

{% gridExampleRunner title="Value Formatter Example" name="value-formatter-example"  exampleHeight=550 /%}

_Note: Read our [Value Formatter](./value-formatters/) page for more information on formatting cell values_


{% /if %}

{% if isFramework("vue") %}
<!-- Format Cell Values-->

The data supplied to the grid usually requires some degree of formatting. For basic text formatting we can use **Value Formatters**.

**Value Formatters** are basic functions which take the value of the cell, apply some basic formatting, and return a new value to be displayed by the grid. Let's try this by adding the `valueFormatter` property to our 'price' column and returning the formatted value:

```jsx
const colDefs = ref([
    { field: "price", valueFormatter: (params) => { return '£' + params.value.toLocaleString(); } },
    // ...
]);
```

The grid should now show the formatted value in the 'price' column:

{% gridExampleRunner title="Value Formatter Example" name="value-formatter-example"  exampleHeight=550 /%}

_Note: Read our [Value Formatter](./value-formatters/) page for more information on formatting cell values_
{% /if %}

## Custom Cell Components

{% if isFramework("javascript") %}
<!-- Custom Cell Components-->

**Value Formatters** are useful for basic formatting, but for more advanced use-cases we can use **Cell Renderers** instead.

**Cell Renderers** allow you add custom HTML & JS within cells. To use a Cell Renderer, set the `cellRenderer` prop on a column, with the value as the name of your Cell Renderer.

Let's try this by creating a new component to display the company logo in the 'company' column:

```jsx
class CompanyLogoRenderer {
    eGui;

    // Optional: Params for rendering. The same params that are passed to the cellRenderer function.
    init(params) {
        let companyLogo = document.createElement('img');
        companyLogo.src = `https://www.ag-grid.com/example-assets/space-company-logos/${params.value.toLowerCase()}.png`
        companyLogo.setAttribute('style', 'display: block; width: 25px; height: auto; max-height: 50%; margin-right: 12px; filter: brightness(1.1)');
        let companyName = document.createElement('p');
        companyName.textContent = params.value;
        companyName.setAttribute('style', 'text-overflow: ellipsis; overflow: hidden; white-space: nowrap;');
        this.eGui = document.createElement('span');
        this.eGui.setAttribute('style', 'display: flex; height: 100%; width: 100%; align-items: center')
        this.eGui.appendChild(companyLogo)
        this.eGui.appendChild(companyName)
    }

    // Required: Return the DOM element of the component, this is what the grid puts into the cell
    getGui() {
        return this.eGui;
    }

    // Required: Get the cell to refresh.
    refresh(params) {
        return false
    }
}
```

And then adding `cellRenderer: CompanyLogoRenderer` to the 'company' column definition:

```jsx
columnDefs: [
    {
        field: "company",
        cellRenderer: CompanyLogoRenderer
    },
    // ...
],
```

Now, when we run the grid, we should see a company logo next to the name:

{% gridExampleRunner title="Cell Renderer Example" name="cell-renderer-example"  exampleHeight=550 /%}

_Note: Read our [Cell Components](./component-cell-renderer/) page for more information on using custom components in cells_


{% /if %}

{% if isFramework("react") %}
<!-- Custom Cell Components-->

**Value Formatters** are useful for basic formatting, but for more advanced use-cases we can use **Cell Renderers** instead.

**Cell Renderers** allow you to use your own React components within cells. To use a custom component, set the `cellRenderer` prop on a column, with the value as the name of your component.

Let's try this by creating a new component to display the company logo in the 'company' column:

```jsx
// Custom Cell Renderer (Display flags based on cell value)
const CompanyLogoRenderer = ({ value }) => (
    <span style={{ display: "flex", height: "100%", width: "100%", alignItems: "center" }}>{value && <img alt={`${value} Flag`} src={`https://www.ag-grid.com/example-assets/space-company-logos/${value.toLowerCase()}.png`} style={{display: "block", width: "25px", height: "auto", maxHeight: "50%", marginRight: "12px", filter: "brightness(1.1)"}} />}<p style={{ textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap" }}>{value}</p></span>
);
```

And then adding the `cellRenderer` prop on our 'company' column to use our component:

```jsx
const [colDefs] = useState([
    {
        field: "company",
        // Add component to column via cellRenderer
        cellRenderer: CompanyLogoRenderer
    },
    // ...
]);
```

Now, when we run the grid, we should see a company logo next to the name:

{% gridExampleRunner title="Cell Renderer Example" name="cell-renderer-example"  exampleHeight=550 /%}

_Note: Read our [Cell Components](./component-cell-renderer/) page for more information on using custom components in cells_


{% /if %}

{% if isFramework("angular") %}
<!-- Custom Cell Components-->

**Value Formatters** are useful for basic formatting, but for more advanced use-cases we can use **Cell Renderers** instead.

**Cell Renderers** allow you to use your own components within cells. To use a custom component, add the `cellRenderer` prop to a column and set the value to the name of your component.

Let's try this by creating a new component to display the company logo in the 'company' column:

```jsx
// Custom Cell Renderer Component
@Component({
    selector: 'app-company-logo-renderer',
    standalone: true,
    imports: [CommonModule],
    template: `<span>@if(value){<img [alt]="value" [src]="'https://www.ag-grid.com/example-assets/space-company-logos/' + value.toLowerCase() + '.png'" /> <p>{{ value }}</p>}</span>`,
    styles: ["img {display: block; width: 25px; height: auto; max-height: 50%; margin-right: 12px; filter: brightness(1.2);} span {display: flex; height: 100%; width: 100%; align-items: center} p { text-overflow: ellipsis; overflow: hidden; white-space: nowrap }"]
    })

    export class CompanyLogoRenderer implements ICellRendererAngularComp {
    // Init Cell Value
    public value!: string;
    agInit(params: ICellRendererParams): void {
        this.value = params.value;
    }

    refresh(params: ICellRendererParams): boolean {
        this.value = params.value;
        return true;
    }
}
```

And then adding the cellRenderer prop on our 'company' column to use our component:

```ts
colDefs: ColDef[] = [
    {
        field: "company",
        cellRenderer: CompanyLogoRenderer // Render a custom component
    }
    // ...
];
```

Now, when we run the grid, we should see a company logo next to the name:

{% gridExampleRunner title="Cell Renderer Example" name="cell-renderer-example"  exampleHeight=550 /%}

_Note: Read our [Cell Components](./component-cell-renderer/) page for more information on using custom components in cells_


{% /if %}

{% if isFramework("vue") %}
<!-- Custom Cell Components-->

**Value Formatters** are useful for basic formatting, but for more advanced use-cases we can use **Cell Renderers** instead.

**Cell Renderers** allow you to use your own components within cells. To use a custom component, set the `cellRenderer` prop on a column, with the value as the name of your component.

Let's try this by creating a new component to display the company logo in the 'company' column:

```jsx
const CompanyLogoRenderer = {
    template:
        `
        <span style="display: flex; height: 100%; width: 100%; align-items: center;">
            <img :src="'https://www.ag-grid.com/example-assets/space-company-logos/' + cellValueLowerCase + '.png'" style="display: block; width: 25px; height: auto; max-height: 50%; margin-right: 12px; filter: brightness(1.1);" />
            <p style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">{{ cellValue }}</p>
        </span>
        `,
    setup(props) {
        const cellValue = props.params.value;
        const cellValueLowerCase = cellValue.toLowerCase();
        return {
            cellValue,
            cellValueLowerCase
        };
    },
};
```

And then adding the `cellRenderer` property to the 'company' column:

```jsx
const App = {
    components: {
        AgGridVue,
        companyLogoRenderer: CompanyLogoRenderer
    },
    setup() {
        const colDefs = ref([
            { field: "company", cellRenderer: "companyLogoRenderer" },
            // ...
        ]);
        // ...
    }
    // ...
}
```

Now, when we run the grid, we should see a company logo next to the name:

{% gridExampleRunner title="Cell Renderer Example" name="cell-renderer-example"  exampleHeight=550 /%}

_Note: Read our [Cell Components](./component-cell-renderer/) page for more information on using custom components in cells_


{% /if %}

## Handle Grid Events

{% if isFramework("javascript") %}
<!-- Handle Grid Events-->

In the last section of this tutorial we're going to hook into events raised by the grid using _**Grid Events**_.

To be notified of when an event is raised by the grid we need to add the relevant `on[EventName]` property to our Grid Options, and provide a function to handle the event.

Let's try this out by enabling cell editing in our DefaultColDefs with `editable: true` and hooking into the `onCellValueChanged` event to log the new value to the console:

```jsx
const gridOptions = {
    // Configurations applied to all columns
    defaultColDef: {
        editable: true,
        // ...
    },
    // Log new value when cell value changes
    onCellValueChanged: (event) => {
        console.log(`New Cell Value: ${event.value}`)
    }
    // ...
}
```

Now, when we click on a cell we should be able to edit it and see the new value logged to the console:

{% gridExampleRunner title="Complete Example" name="grid-events-example"  exampleHeight=550 /%}

_Refer to our [Grid Events](./grid-events/) documentation for a full list of events raised by the grid_


{% /if %}

{% if isFramework("react") %}
<!-- Handle Grid Events-->

In the last section of this tutorial we're going to hook into events raised by the grid using _**Grid Events**_.

To be notified of when an event is raised by the grid we need to use the relevant `on[EventName]` prop on the grid component. Let's try this out by enabling cell editing with `editable: true` and hooking into the `onCellValueChanged` event to log the new value to the console:

```jsx
const defaultColDef = useMemo(() => ({
    editable: true, // Enable editing on all cells
    // ...
}))

<div style={{ width: 600, height: 500 }}>
    <AgGridReact
        // Hook into CellValueChanged event and log value
        onCellValueChanged={event => console.log(`New Cell Value: ${event.value}`)}
        // ...
    />
</div>
```

Now, when we click on a cell we should be able to edit it and see the new value logged to the console:

{% gridExampleRunner title="Complete Example" name="grid-events-example"  exampleHeight=550 /%}

_Refer to our [Grid Events](./grid-events/) documentation for a full list of events raised by the grid_


{% /if %}

{% if isFramework("angular") %}
<!-- Handle Grid Events-->

In the last section of this tutorial we're going to hook into events raised by the grid using _**Grid Events**_.

To be notified of when an event is raised by the grid we need to add the relevant event name attribute to the `ag-grid-angular` component.

Let's try this out by enabling cell editing with `editable: true` on the Default Column Definitions:

```ts
// Default Column Definitions: Apply configuration across all columns
defaultColDef: ColDef = {
    editable: true
    // ...
}
```

Next, lets create a function to handle the event:

```jsx
// Handle cell editing event
onCellValueChanged = (event: CellValueChangedEvent) => {
    console.log(`New Cell Value: ${event.value}`)
}
```

Finally, let's add the `gridReady` attribute to the `ag-grid-angular` component, with the value as the function we've just created:

```ts
<!-- The AG Grid component, with various Grid Option properties -->
<ag-grid-angular
    (gridReady)="onGridReady($event)"
    ...
/>
```

Now, when we click on a cell we should be able to edit it and see the new value logged to the console:

{% gridExampleRunner title="Complete Example" name="grid-events-example"  exampleHeight=550 /%}

_Refer to our [Grid Events](./grid-events/) documentation for a full list of events raised by the grid_


{% /if %}

{% if isFramework("vue") %}
<!-- Handle Grid Events-->

In the last section of this tutorial we're going to hook into events raised by the grid using _**Grid Events**_.

To be notified of when an event is raised by the grid we need to use the relevant `@[event-name]` attribute on the `ag-grid-vue` component. Let's try this out by enabling cell editing with `editable: true` and hooking into the `onCellValueChanged` event to log the new value to the console:

```jsx
const App = {
    template:
        `
        <ag-grid-vue
            ...
            @cell-value-changed="onCellValueChanged"
        >
        </ag-grid-vue>
        `,
    methods: {
        onCellValueChanged(event) {
            console.log(`New Cell Value: ${event.value}`);
        }
    },
    setup() {
        const defaultColDef = ref({
            editable: true,
            // ...
        });
        // ...
    }
    // ...
}
```

Now, when we click on a cell we should be able to edit it and see the new value logged to the console:

{% gridExampleRunner title="Complete Example" name="grid-events-example"  exampleHeight=550 /%}

_Refer to our [Grid Events](./grid-events/) documentation for a full list of events raised by the grid_
{% /if %}

## Test Your Knowledge

<!-- Test Your Knowledge-->

Let's put what you've learned so far into action by modifying the grid:

1) Enable filtering on all columns

   _Hint: `filter` is a Column Definition property_

1) Enable multiple row selection

   _Hint: `selection` is a Grid Option property_

1) Log a message to the console when a row selection is changed

   _Hint: `onSelectionChanged` is a Grid Event_

1) Format the Date column using `.toLocaleDateString()`;

   _Hint: Use a `valueFormatter` on the 'Date' column to format its value_

1) Add a Cell Renderer to display [ticks](https://www.ag-grid.com/example-assets/icons/tick-in-circle.png) and [crosses](https://www.ag-grid.com/example-assets/icons/cross-in-circle.png) in place of checkboxes on the 'Successful' column:

   _Hint: Use a `cellRenderer` on the 'successful' column_

Once complete, your grid should look like the example below. If you're stuck, check out the source code to see how its done:

{% gridExampleRunner title="Testing Example" name="testing-example"  exampleHeight=550 /%}

## Summary
<!-- Summary-->

Congratulations! You've completed the tutorial and built your first grid. By now, you should be familiar with the key concepts of AG Grid:

- **Row Data:** Your data, in JSON format, that you want the grid to display.

- **Column Definitions:** Define your columns and control column-specific functionality, like sorting and filtering.

- **Default Column Definitions:** Similar to Column Definitions, but applies configurations to all columns.

- **Grid Options:** Configure functionality which extends across the entire grid.

- **Grid Events:** Events raised by the grid, typically as a result of user interaction.

- **Value Formatters:** Functions used for basic text formatting

- **Cell Renderers:** Add your own components to cells

## Next Steps

<!-- Next Steps-->

Browse our guides to dive into specific features of the grid:

- [Theming & Styling](./theming/)
- [Testing](./testing/)
- [Security](./security/)
